// 类型保护  基于js + ts （收窄）通过判断，去识别类型，核心就是进行类型的收窄
// js 手段来判断类型 typeof(基础类型) instanceof(类类型) in(接口类型，可辨识类型) 可以类型的收窄
// ts很多情况下
// 1）需要使用联合类型, 默认情况下只能使用公共的方法，识别类型 （针对某个类型进行处理）；
// 2）自定义类型保护 ==> 自己决定返回true的时候是什么类型
// 3）null保护 ==> 判断非空后再去使用
// 3）唯一标识
// 除了我们上面提供的这些，只要能通过结构来判断的，都能达到类型保护的特性
// typeof(基础类型)  instanceof(类类型)  in(接口类型，可辨识类型)
// 1）typeof(基础类型)
function fn(val: string | number) {
  if (typeof val === "string") {
    val.charAt(0); // string
  } else {
    val.toFixed; // number
  }
}
class Cat {
  cry() {}
}
class Dog {
  eat() {}
}
function getInstance(clazz: { new (...args: any[]): Cat | Dog }) {
  return new clazz();
}
// 2）instanceof(类类型)
const instance = getInstance(Cat);
if (instance instanceof Cat) {
  instance.cry;
} else {
  instance.eat;
}

// 3）ts可辨识类型 ,js属性区别 通过in来实现
/*
interface Bird {
  kind: "鸟"; // ts可辨识类型,接口的常量，用于判断
  fly: string; // 属性区别 通过in来实现
}
interface Fish {
  kind: "鱼"; // ts可辨识类型,接口的常量，用于判断
  swiming: string; // 属性区别 通过in来实现
}

function getAimal(val: Bird | Fish) {
  // in 基于差异化来辨别
  if ("fly" in val) {
    val;
  } else {
    val;
  }
  // ts 辨别方法， 联合类型可以访问共同存在的类型,进行判断
  if (val.kind == "鸟") {
    val.fly;
  } else {
    val.swim;
  }
}*/
// 通过各种判断来缩小范围  生命周期 []  只要能通过结构来判断的，都能达到类型保护的特性
function ensureArray<T>(input: T | T[]) {
  if (Array.isArray(input)) {
    return input;
  } else {
    return [input];
  }
}
let r1 = ensureArray("abc");
let r2 = ensureArray(["abc"]);

// 函数的嵌套不识别的问题  ? ! if 都有缩小范围的用途 (基于上下文类型的推导，会因为作用域的变化 而产生问题)
// ! 一定存在的意思   ?取值

function addType(val?: number) {
  // 断言就是自己说的算，出错了自己承担
  val = val || 0;
  return function (type: string) {
    return type + (val as number).toFixed(); // ts 无法识别的时候 需要用断言
  };
}
addType(100)("$");

// is 语法 ts语法  主要在辅助的方法中用的比较多

interface Bird {
  kind: "鸟";
  fly: string;
}
interface Fish {
  kind: "鱼";
  swim: string;
}
// 这是自定义的条件
// function isBird(val: Bird | Fish) {
//   // ts的返回值类型
//   // 函数的名字 和返回值是无关的
//   // true是bird 还是false 是bird
//   return "fly" in val;
// }
//  val is Bird自定义类型保护，自定义类型保护==> 自己决定返回true的时候是什么类型
function isBird(val: Bird | Fish): val is Bird {
  // ts的返回值类型
  // 函数的名字 和返回值是无关的
  // true是bird 还是false 是bird
  return "fly" in val;
}
function getAimal(val: Bird | Fish) {
  // 基于差异化来辨别
  if (isBird(val)) {
    val;
  } else {
    val;
  }
}

// 收缩范围
// 参数num ==> num: number | undefined
const addPrefix = (num?: number) => {
  num = num || 100;
  // 上一步可以实现类型收窄 ===>num: number
  // ts类型保护，是静态的,没有执行，只针对当前作用域的，
  // 下一层，num的值依旧是 num: number | undefined
  num;
  function fn() {
    //内部方法无法解析外层函数的默认值 =====> num的值依旧是 num: number | undefined
    // 断言
    // return "人民币:" + num!.toString();
    if (num) {
      // 判断
      return "人民币:" + num.toString();
    }
    // 无论 断言还是判断 只要能通过结构来判断的，都能达到类型保护的特性
  }
};

export {};
